/**
 * Copyright (c) 2011 - 2012 National Library of Medicine
 *
 * Contact: tomasz.adamusiak@nih.gov;
 * 
 * This file is part of LOwlINC
 * 
 * LOwlINC is free software: you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation; either version 3 of the License, or (at your option) any
 * later version.
 * 
 * LOwlINC is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
 * details.
 * 
 * You should have received a copy of the GNU Lesser General Public License along
 * with LOwlINC. If not, see <http://www.gnu.org/licenses/>.
 */
package gov.nih.nlm.lowlinc.csv;

import gov.nih.nlm.lowlinc.accessionwrapper.LOINCID;
import gov.nih.nlm.lowlinc.accessionwrapper.LOINCPartID;
import gov.nih.nlm.lowlinc.accessionwrapper.LOINCTermID;
import gov.nih.nlm.lowlinc.core.LowlincConfig;
import gov.nih.nlm.lowlinc.owlapi.LowlincException;
import gov.nih.nlm.lowlinc.owlapi.Ontologies;

import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import org.apache.log4j.Logger;
import org.semanticweb.owlapi.model.IRI;
import org.semanticweb.owlapi.model.OWLClass;
import org.semanticweb.owlapi.model.OWLClassExpression;

/**
 * @author Tomasz Adamusiak
 * 
 */
public class InferredAxialOWLParser {
	private static final Logger log = Logger
			.getLogger(InferredAxialOWLParser.class);
	private String[] headerCSV;
	private final AxialGraph graph = new AxialGraph();
	private Map<LOINCID, String> labels = new HashMap<>();
	private PrintWriter out_attributes;
	private static PrintWriter out_nodes;

	public AxialGraph getGraph() {
		return graph;
	}

	public InferredAxialOWLParser(Map<LOINCID, String> labels)
			throws LowlincException {
		this.labels = labels;
		// record
		try {
			out_nodes = new PrintWriter(new FileWriter(
					LowlincConfig.getString("CYTOSCAPE_NODES.path")));
			out_attributes = new PrintWriter(new FileWriter(
					LowlincConfig.getString("CYTOSCAPE_ATTRIBUTES.path")));
			log.info("SAVING "
					+ LowlincConfig.getString("CYTOSCAPE_NODES.path"));
			log.info("SAVING "
					+ LowlincConfig.getString("CYTOSCAPE_ATTRIBUTES.path"));
		} catch (IOException e) {
			throw new LowlincException(e);
		}
		// load labels
		Ontologies.loadOntology(LowlincConfig.getString("SAVE_PATH"));
		log.info("Regular loaded");
		for (OWLClass cls : Ontologies.getOntology().getClassesInSignature()) {
			// skip inactive
			if (cls.getSuperClasses(Ontologies.getOntology()).contains(
					Ontologies.getDeprecatedParent())) {
				continue;
			}
			// FIXME: ugly code
			try {
				labels.put(new LOINCPartID(cls), Ontologies.getLabel(cls));
			} catch (LowlincException e) {
				labels.put(new LOINCTermID(cls), Ontologies.getLabel(cls));
			}

		}

		// load inferred axial graph
		Ontologies.loadOntology(LowlincConfig.getString("INFERRED_SAVE_PATH"));
		log.info("inferred loaded");

		IRI obsIRI = IRI.create(LowlincConfig.getString("LOINC_IRI")
				+ LowlincConfig.getString("OBSERVATION_ROOT_ACCESSION"));
		OWLClass cls = Ontologies.getManager().getOWLDataFactory()
				.getOWLClass(obsIRI);

		Set<LOINCTermID> sEquis = new HashSet<>();

		for (OWLClassExpression subclass : cls.getSubClasses(Ontologies
				.getOntology())) {
			if (subclass.isAnonymous()) {
				continue;
			}
			// observation
			if (subclass.asOWLClass().getIRI().toString().contains("OBS_")) {
				for (OWLClassExpression eqi : subclass.asOWLClass()
						.getEquivalentClasses(Ontologies.getOntology())) {
					sEquis.add(new LOINCTermID(subclass));
				}
				processChildren(sEquis, subclass.asOWLClass());
			}
		}
		// 47k (73%) LOINC tests
		// 27k (32%) LOINC parts
		Ontologies.releaseOntology();

		log.info("Equiv observations " + sEquis.size());

		out_nodes.close();
		out_attributes.close();

		// TODO: orphaned axials
		log.info(graph.getParts().size() + " axial parts loaded");
		log.info(graph.getTerms().size() + " axial terms loaded");
	}

	private void processChildren(Set<LOINCTermID> sEquis, OWLClass node)
			throws LowlincException {
		LOINCID parentID = new LOINCTermID(node);
		for (OWLClassExpression subclass : node.getSubClasses(Ontologies
				.getOntology())) {
			if (subclass.isAnonymous()) {
				continue;
			}
			LOINCID childID = new LOINCTermID(subclass);
			// record
			out_nodes.println(childID.getID() + "," + parentID.getID());
			out_attributes.println(childID.getID() + "," + labels.get(childID));
			out_attributes.println(parentID.getID() + ","
					+ labels.get(parentID));

			graph.addParentChild(parentID, childID);
			// observation
			if (subclass.asOWLClass().getIRI().toString().contains("OBS_")) {
				for (OWLClassExpression eqi : subclass.asOWLClass()
						.getEquivalentClasses(Ontologies.getOntology())) {
					sEquis.add(new LOINCTermID(eqi));
				}
			}
			processChildren(sEquis, subclass.asOWLClass());
		}
	}
}
